import re
from collections import Counter

EXCLUSIONS = {
    'duplInheritedMember': ["defines member function with name 'iddObjectType' also defined in its parent class"]
}

def colorize(lines):
    def bold(s):
        return "\x1b[1m{}\x1b[0m".format(s)

    def red(s):
        return "\x1b[31m{}\x1b[0m".format(s)

    def green(s):
        return "\x1b[32m{}\x1b[0m".format(s)

    def yellow(s):
        return "\x1b[33m{}\x1b[0m".format(s)

    def blue(s):
        return "\x1b[34m{}\x1b[0m".format(s)

    def magenta(s):  # purple
        return "\x1b[35m{}\x1b[0m".format(s)

    def cyan(s):
        return "\x1b[36m{}\x1b[0m".format(s)

    def format_severity(txt, severity):
        """
        http://cppcheck.sourceforge.net/devinfo/doxyoutput/classSeverity.html
        enum:
            none, error, warning, style, performance,
            portability, information, debug
        """
        if severity == "none":
            return txt
        if severity == "error":
            return red(txt)
        if severity == "warning":
            return yellow(txt)
        if severity == "style":
            return blue(txt)
        if severity == "performance":
            return cyan(txt)
        if severity == "portability":
            return magenta(txt)
        if severity == "information":
            return green(txt)
        if severity == "debug":
            return txt

        return txt

    re_message = re.compile(
        r"\[(?P<file>.*):(?P<line>.*?)\]:" r"\((?P<severity>.*?)\),\[(?P<id>.*?)\]," r"(?P<message>.*)"
    )

    colored_lines = []
    matched_messages = []

    colored_lines = []
    matched_messages = []

    for line in lines:
        m = re_message.match(line)
        if m:
            d = m.groupdict()
            if d['id'] in EXCLUSIONS:
                if any([x in d['message'] for x in EXCLUSIONS[d['id']]]):
                    continue
            matched_messages.append(d)
        else:
            colored_lines.append(red(line))

    severity_order = ["error", "warning", "performance", "portability", "style", "information", "debug", "none"]

    counter = Counter(d["severity"] for d in matched_messages)
    summary_line = "\n\n==========================================\n"
    summary_line += "             {}:\n".format(bold(red("CPPCHECK Summary")))
    summary_line += "------------------------------------------"

    for severity in severity_order:
        n_severity = counter[severity]
        summary_line += "\n * "
        if n_severity:
            summary_line += format_severity(n_severity, severity)
        else:
            # summary_line += green("No {}(s)".format(severity))
            summary_line += green("No")
        summary_line += " {}(s)".format(format_severity(severity, severity))

    summary_line += "\n==========================================\n\n"

    n_errors = counter["error"]
    # if n_errors:
    #     summary_line += red("{} Errors".format(n_errors))
    # else:
    #     summary_line = green("No Errors")

    n_warnings = counter["warning"]
    # if n_warnings:
    #     summary_line += yellow("{} Warnings".format(n_warnings))
    # else:
    #     summary_line = green("No Warnings")

    n_styles = counter["style"]
    n_performances = counter["performance"]
    n_portabilities = counter["portability"]
    # n_informations = counter['information']

    # n_debugs = counter['debug']

    # Start by sorting by filename
    matched_messages.sort(key=lambda d: d["file"])
    matched_messages.sort(key=lambda d: severity_order.index(d["severity"]))

    # Now sort by the severity we cared about
    for d in matched_messages:
        f = d["file"]
        line = d["line"]
        severity = d["severity"]
        iid = d["id"]
        message = d["message"]

        colored_lines.append(
            "[{f}:{line}]:({severity}),[{i}],{message}".format(
                f=magenta(f),  # format_severity(f, severity),
                line=green(line),
                severity=format_severity(severity, severity),
                i=bold(iid),
                message=message,
            )
        )

    return (colored_lines, summary_line, n_errors, n_warnings, n_performances, n_portabilities, n_styles)


if __name__ == "__main__":
    with open("cppcheck.txt", "r") as f:
        content = f.read()

    lines = content.splitlines()
    (colored_lines, summary_line, n_errors, n_warnings, n_performances, n_portabilities, n_styles) = colorize(lines)
    print(summary_line)
    # sys.stdout.writelines(colored_lines)
    print("\n".join(colored_lines))
    n_tot = n_errors + n_warnings + n_performances + n_portabilities + n_styles
    if n_tot > 0:
        exit(1)
